package cloud

import (
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"gitee.com/tomatomeatman/golang-repository/bricks/model/msgentity"
	"gitee.com/tomatomeatman/golang-repository/bricks/utils/ginutil"
	Log "github.com/cihub/seelog"
	"gopkg.in/ini.v1"
)

var (
	appCfg             *ini.File //配置文件变量
	glbAppiCloudApp    = 0       //是否要加入分布式系统(0:待初始化;1:是;2:否)
	glbAppiCloudSystem = 0       //是否要启用桥接(0:待初始化;1:是;2:否)
	once               sync.Once
)

/**
 * 初始化
 */
func init() {
	if !IsCloudServe() {
		return
	}

	go ginutil.ControllerRegister("/cloud/monitor", CloudMonitor, ginutil.POST, ginutil.GET)
}

/**
 * 注册服务到注册中心
 */
func RegistraCloud() {
	if !IsCloudServe() {
		return
	}

	cloudCenterSite := readConfigKey("CloudCenter", "Site", "")
	cloudCenterUser := readConfigKey("CloudCenter", "User", "")
	cloudCenterPassword := readConfigKey("CloudCenter", "Password", "")
	DomainName := readConfigKey("System", "DomainName", "")
	DomainPort := readConfigKey("System", "DomainPort", "")

	Port := readConfigKey("System", "Port", "8080")
	Name := readConfigKey("System", "Name", "")

	var json strings.Builder
	json.WriteString("{\"sSign\":\"")
	json.WriteString(Name)
	json.WriteString("Server\",\"serverPort\":\"")
	json.WriteString(Port)
	json.WriteString("\",\"serverIp\":\"unknown\",\"domainName\":\"")
	json.WriteString(DomainName)
	json.WriteString("\",\"domainPort\":\"")
	json.WriteString(DomainPort)
	json.WriteString("\"}")

	var host strings.Builder
	host.WriteString("http://")
	host.WriteString(cloudCenterSite)
	host.WriteString("/add")

	params := url.Values{}
	params.Add("user", cloudCenterUser)
	params.Add("key", cloudCenterPassword)
	params.Add("sSign", Name+"Server")
	params.Add("sRegisterTxt", url.QueryEscape(json.String()))

	appCfg = nil //释放
	urlStr := strings.Replace(host.String(), "http://http://", "http://", 1)

	for {
		bl, errStr := httpGet(urlStr, params)
		if bl {
			//fmt.Println("注册服务成功")
			Log.Info("注册服务成功")
			return
		}

		Log.Error("注册服务失败,返回内容:", errStr)
		time.Sleep(time.Second * 5) //休眠5秒
	}
}

// GET请求
func httpGet(urlStr string, params url.Values) (bool, string) {
	urlStr = urlStr + params.Encode() // 构造完整的 URL

	// 发送 GET 请求
	resp, err := http.Get(urlStr)
	if err != nil {
		Log.Error("GET请求URL发生异常:", err)
		return false, err.Error()
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		Log.Error("读取响应体发生异常:", err)
		return false, string(body)
	}

	return true, ""
}

// #region @Api {title=中心监听接口}
// @return {type=json explainType=MsgEntity<string> explain=返回响应}
// @RequestMapping {name=ServerIp type=GET value=/cloud/monitor}
// #endregion
func CloudMonitor(ctx ginutil.Context) interface{} {
	return msgentity.Success(time.Now().Format("2006-01-02 15:04:05"), "访问成功")
}

/**
 * 判断是否是分布式系统
 */
func IsCloudServe() bool {
	if glbAppiCloudApp != 0 {
		return glbAppiCloudApp == 1
	}

	if !(hasSection("CloudCenter")) {
		glbAppiCloudApp = 2
		return false
	}

	glbAppiCloudApp = 1
	return true
}

// 判断程序是否启用桥接
func IsCloudSystem() bool {
	if glbAppiCloudSystem != 0 {
		return glbAppiCloudSystem == 1
	}

	if hasSection("CloudSystem") {
		glbAppiCloudSystem = 1
		return true
	}

	glbAppiCloudSystem = 2
	return false
}

// 判断配置组是否存在
func hasSection(sectionName string) bool {
	iniCfg()

	section, _ := appCfg.GetSection(sectionName) // return appCfg.HasSection(sectionName)//这种方式不安全

	if section == nil {
		return false
	}

	if len(section.Keys()) == 0 {
		return false
	}

	return true
}

// 初始化配置文件变量
func iniCfg() {
	once.Do(func() {
		root := ""
		exePath, err := os.Executable()
		if err != nil {
			root = "."
		}

		root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

		configFilePath := strings.Replace(root+"/config/app.ini", "\\", "/", -1)

		_, err = os.Stat(configFilePath) //os.Stat获取文件信息
		if err != nil {
			if !os.IsExist(err) {
				Log.Error("配置文件不存在", err)
				return
			}
		}

		appCfg, err = ini.Load(configFilePath)
		if err != nil {
			Log.Error("配置文件读取错误", err)
			return
		}
	})
}

// 读取配置值
func readConfigKey(section, key, def string) string {
	title := appCfg.Section(section)
	value, _ := title.GetKey(key)
	if value == nil {
		return def
	}

	return value.String()
}
